<template>
  <view v-if="showState" class="mxp-toast">
    <view
      v-if="data.mask"
      :style="[styleObj.maskStyle, { transitionDuration: `${duration}ms`, opacity }]"
      class="mask"
      @touchmove.stop.passive="preventClick"
    ></view>
    <view
      class="toast-view"
      :style="[{ zIndex: data.zIndex! + 1, transform, transitionDuration: `${duration}ms`, opacity }]"
      @click.stop.prevent="preventClick"
    >
      <view
        style="display: flex; align-items: center; justify-content: center; padding: 10px 15px; border-radius: 10px"
        :style="{ background: data.background }"
      >
        <view class="left-view">
          <mxp-icon :name="data.icon" :size="data.iconSize" :color="data.iconColor"></mxp-icon>
          <text class="msg-text" :style="{ fontSize: data.msgSize, color: data.msgColor }">
            {{ data.msg }}
          </text>
        </view>
        <mxp-icon
          v-if="data.showClose"
          class="close-icon"
          name="guanbi"
          :size="data.closeIconSize"
          :color="data.closeIconColor"
          :cusStyle="{ padding: '0px', marginLeft: '8px' }"
          @click="hide"
        ></mxp-icon>
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
  import MxpIcon from '../mxp-icon/mxp-icon.vue';
  import { removeObjectEmpty } from '../mxp-tool/utils/obj';
  import { type CSSProperties, type PropType, nextTick, ref, shallowReactive, shallowRef } from 'vue';
  import type { $AllColorStr, $ColorType, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import { getXPNumber } from '../mxp-tool/utils/dom';
  import type { MxpIconFont } from '../mxp-icon/mxp-icon-font-map';
  import mxpGetSysInfoStore from '../mxp-tool/store/mxp-store-sys-info';
  import { defThemeColor } from '../mxp-tool/theme/theme';
  import { lightenDarkenColorStorage } from '../mxp-tool/utils/color';

  export type $ToastOptions = {
    /** 类型 */
    type?: $ColorType;
    /** 图标  */
    icon?: MxpIconFont;
    /** 背景色 */
    background?: $AllColorStr;
    /** 图标颜色 */
    iconColor?: $AllColorStr;
    /** 图标大小 */
    iconSize?: $SizeUnitStr;
    /** 文本颜色 */
    msgColor?: $AllColorStr;
    /** 文本颜色 */
    msgSize?: $SizeUnitStr;
    /** 是否显示关闭按钮 */
    showClose?: boolean;
    /** 关闭按钮颜色 */
    closeIconColor?: $AllColorStr;
    /** 关闭按钮颜色 */
    closeIconSize?: $SizeUnitStr;
    /** 层级 */
    zIndex?: number;
    /** 延迟关闭时间 */
    delay?: number;
    /** 是否有遮罩 */
    mask?: boolean;
    /** 是否有遮罩 */
    maskBackground?: $AllColorStr;
    /** 执行完成后的回调 */
    complete?: (dara: Omit<$ToastOptions, 'complete'>) => void;
  };

  type $Data = $ToastOptions & { msg?: number | string };

  defineOptions({
    name: 'mxp-toast',
  });

  const props = defineProps({
    /** 是否显示关闭按钮 */
    showClose: { type: Boolean, default: false }, // eslint-disable-line vue/no-unused-properties
    /** 是否自定义导航栏  */
    customNav: { type: Boolean, default: false },
    /** 顶部偏移量 (如自定义导航栏等) */
    offsetTop: { type: String as PropType<$SizeUnitStr>, default: '0px' },
    /** 配置 */
    options: { type: Object as PropType<$ToastOptions>, default: () => ({}) },
    /** 动画持续时间 (注意不是显示停留时间，而是显示或隐藏动画的过渡时间) */
    duration: { type: Number, default: 300 },
  });

  const iconObj: Record<$ColorType, MxpIconFont> = {
    error: 'guanbi1',
    warning: 'jinggao',
    success: 'queding',
    primary: 'jinggao',
    info: 'jinggao',
  };

  const opacity = ref(0);
  const transform = ref('translateY(-100%)');
  const animationTimeout = ref<NodeJS.Timeout | undefined>(undefined);

  /** 默认配置 */
  const defaultData: $Data = {
    msg: '',
    icon: iconObj.primary,
    background: lightenDarkenColorStorage(defThemeColor.value.primary, 0.1)! as $AllColorStr,
    iconColor: defThemeColor.value.primary,
    iconSize: '14px',
    msgColor: defThemeColor.value.primary,
    msgSize: '14px',
    closeIconColor: defThemeColor.value.primary,
    closeIconSize: '14px',
    zIndex: 9999,
    delay: 1500,
    mask: false,
    maskBackground: 'rgba(0,0,0,0.3)',
  };

  const data = shallowRef<$Data>({ ...defaultData, msg: '' });
  const styleObj = shallowReactive({
    maskStyle: {} as CSSProperties,
  });

  /** 显示状态 */
  const showState = ref(false);

  /**
   * 显示
   * @param msg - 消息内容
   * @param type - 类型 'error' | 'warning' | 'success' | 'primary' | 'info'
   * @param time - 动画时间
   * @param mask - 是否显示遮罩
   */
  function show(msg: number | string, type?: $ColorType, param: $ToastOptions = {}) {
    const newOp: $Data = { ...removeObjectEmpty(defaultData), ...removeObjectEmpty(props.options), ...removeObjectEmpty(param) };
    const _type = type || param.type || 'primary';
    const icon = _type in defThemeColor.value ? iconObj[_type] : iconObj.primary;

    newOp.msg = msg || '';
    newOp.icon = param.icon || icon;
    newOp.background = param.background || (lightenDarkenColorStorage(defThemeColor.value[_type], 0.1)! as $AllColorStr);
    newOp.iconColor = param.iconColor || defThemeColor.value[_type];
    newOp.msgColor = param.msgColor || defThemeColor.value[_type];
    newOp.closeIconColor = param.closeIconColor || defThemeColor.value[_type];
    data.value = newOp;

    const sys = mxpGetSysInfoStore().getSysInfo();
    const customNavHeight = props.customNav ? sys.value.safeAreaInsets!.bottom + 44 : 0;
    styleObj.maskStyle = {
      height: `${sys.value.windowHeight}px`,
      width: `${sys.value.windowWidth}px`,
      top: `${sys.value.windowTop + customNavHeight + getXPNumber(props.offsetTop)}px`,
      left: '0px',
      zIndex: data.value.zIndex,
      position: 'fixed',
      backgroundColor: data.value.maskBackground || 'rgba(0, 0, 0, 0.3)',
    };

    showState.value = true;
    opacity.value = 0;
    transform.value = `translateY(-100%)`;
    animationTimeout.value && clearTimeout(animationTimeout.value);
    nextTick(() => {
      setTimeout(() => {
        opacity.value = 1;
        transform.value = `translateY(${sys.value.windowTop + customNavHeight + getXPNumber(props.offsetTop) + 50}px)`;
        animationTimeout.value = setTimeout(() => {
          hide();
        }, data.value.delay);
      }, 0);
    });
  }

  /**
   * 显示 消息
   */
  function trmShow(msg: number | string, type: $ColorType, duration?: number, mask?: $AllColorStr | boolean) {
    const op: $ToastOptions = {
      delay: duration || defaultData.delay,
      mask: Boolean(mask),
      maskBackground: typeof mask === 'string' && mask ? mask : defaultData.maskBackground,
    };
    show(msg, type, op);
  }
  /**
   * 阻止传递
   */
  function preventClick() {
    // 阻止传递
  }
  /**
   * 显示 Info 消息
   */
  function showInfo(msg: number | string, delay?: number, mask?: $AllColorStr | boolean) {
    trmShow(msg, 'info', delay, mask);
  }
  /**
   * 显示 primary 消息
   */
  function showPrimary(msg: number | string, delay?: number, mask?: $AllColorStr | boolean) {
    trmShow(msg, 'primary', delay, mask);
  }
  /**
   * 显示错误消息
   */
  function showError(msg: number | string, delay?: number, mask?: $AllColorStr | boolean) {
    trmShow(msg, 'error', delay, mask);
  }

  /**
   * 显示警告消息
   */
  function showWarning(msg: number | string, delay?: number, mask?: $AllColorStr | boolean) {
    trmShow(msg, 'warning', delay, mask);
  }

  /**
   * 显示成功消息
   */
  function showSuccess(msg: number | string, duration?: number, mask?: $AllColorStr | boolean) {
    trmShow(msg, 'success', duration, mask);
  }

  /**
   * 关闭
   */
  function hide() {
    animationTimeout.value && clearTimeout(animationTimeout.value);
    opacity.value = 0;
    transform.value = `translateY(-100%)`;
    animationTimeout.value = setTimeout(() => {
      showState.value = false;
      animationTimeout.value = undefined;
    }, data.value.delay);
  }

  defineExpose({
    /** 显示 */
    show,
    /** 显示 Info 消息  */
    showPrimary,
    /** 显示 Info 消息  */
    showInfo,
    /** 显示错误消息 */
    showError,
    /** 显示警告消息 */
    showWarning,
    /** 显示成功消息 */
    showSuccess,
    /** 隐藏 */
    hide,
  });
</script>

<style lang="scss" scoped>
  .mxp-toast {
    .mask {
      opacity: 0;
      transition-timing-function: ease-in-out;
      transition-duration: 0.3s;
      transition-property: opacity;
    }

    .toast-view {
      position: fixed;
      top: 0;
      right: 0;
      left: 0;
      box-sizing: border-box;
      display: flex;
      flex-flow: row nowrap;
      align-items: center;
      justify-content: center;
      width: 80%;
      margin-left: 10%;
      pointer-events: none;
      transition-timing-function: ease-in-out;
      transition-duration: 0.3s;
      transition-property: transform, opacity;
      transform: translateY(-100%);

      .left-view {
        display: flex;
        flex-flow: row nowrap;
        align-items: center;
        justify-content: flex-start;
        width: 100%;
        max-width: 600rpx;

        .msg-text {
          display: flex;
          flex-flow: row wrap;
          margin-left: 8px;
        }
      }
    }
  }
</style>
